//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1999  Microsoft Corporation
--*/

#pragma once
#include <linklist.h>
#include "Ril.h"

#ifdef __cplusplus
extern "C" {
#endif


typedef struct _PDP_CONTEXT_ENTRY
{
	LIST_ENTRY			Node;
	HRESULT 			AsyncCommandID;
	RILNDISGPRSCONTEXT	RilNdisGprsContext; 
	PVOID				pCRilInstance;
} PDP_CONTEXT_ENTRY, *PPDP_CONTEXT_ENTRY;

typedef enum oemndiseventtype_tag
{
	OEM_NDIS_CLOSE_COMPLETE=1,
	OEM_NDIS_OPEN_COMPLETE,
	OEM_NDIS_NUMBER_OF_EVENTS
} OEMNDISEVENTTYPE;
   
typedef struct oemndisipaddress_tag
{
  UCHAR length; 		/* length 0 means unset */
  UCHAR address[16]; 
} OEMNDISIPADDRESS;

typedef struct oemndisipconfig_tag
{
	OEMNDISIPADDRESS	ipAddress;
	OEMNDISIPADDRESS	primaryDnsAddress;
	OEMNDISIPADDRESS	secondaryDnsAddress;
	OEMNDISIPADDRESS	gateway;	
 
} OEMNDISIPCONFIG;

// Structure used for keeping track of the NDIS channels.
typedef struct oemndischannels_tag
{
	DWORD				 ContextID;
	RILNDISGPRSCONTEXT	 RilNdisGprsContext;
	PVOID				 pCRilInstance;
	PVOID				 pCPdpContext;
} OEMNDISCHANNELS, *POEMNDISCHANNELS;

typedef struct oemndisapireference_tag
{
  HRESULT			CommandID; // Used for storing the command ID.
  PVOID 			pCRilInstance;
  DWORD 			ContextID;
  OEMNDISEVENTTYPE	EventType;
  DWORD 			Status;
  RILNDISGPRSCONTEXTRESPONSE    RilNdisGprsContextResponse;
} OEMNDISAPIREFERENCE;

typedef struct oemndisevent_tag
{
	OEMNDISEVENTTYPE	Type;
	OEMNDISIPCONFIG 	IpConfig;
	DWORD				Status; 
	DWORD				ContextID;	// Necessary for Open_Complete, Close_Complete, and IP_Config				
} OEMNDISEVENT;


typedef enum oemndisinitializetype_tag
{
  /* Events generated by OEM */
	OEM_NDIS_INITIALIZE_INIT, 	/* The very first time.						  */
	OEM_NDIS_INITIALIZE_CLOSE,	/* Close a context	  */
} OEMNDISINITIALIZETYPE;

typedef struct oemndisinitialize_tag
{
	DWORD	Size;
    OEMNDISINITIALIZETYPE   dwType;
    RILNDISGPRSCONTEXT    RilNdisGprsContext;
    RILNDISGPRSCONTEXTRESPONSE RilNdisGprsContextResponse;
}OEMNDISINITIALIZE, *POEMNDISINITIALIZE;


#define NDIS_STOP_THREAD_INDEX			0
#define NDIS_RX_QUEUE_INDEX 			1
#define MAX_OEMNDIS_EVENTS				2 

#define MAX_OEMNDIS_CHANNELS   3	 // The number of gprs channels NDIS can open. It should be dynamic.

typedef struct asyncresponse_tag
{
	LIST_ENTRY				Node;	
	OEMNDISAPIREFERENCE 	OemNdisApiReference;  
} ASYNCCOMMAND, *PASYNCCOMMAND;

class CAsyncResponse
{
public:
	CAsyncResponse();
	~CAsyncResponse();
		
	void	AddCommand ( OEMNDISAPIREFERENCE *lpOemNdisApiReference );
	void	ProcessCommand ( const OEMNDISAPIREFERENCE *lpOemNdisApiReference );
	void	RemoveCommand( HRESULT CommandID );
	void	RemoveAllCommands ( DWORD ContextID  );

private:
	void	AsyncListLock(void);
	void	AsyncListUnlock(void);

	LIST_ENTRY	  m_AsyncPendingList;
	LIST_ENTRY	  m_AsyncFreeList;
	CRITICAL_SECTION  m_cs;
	
};

class CRilInstanceNDIS
{
public:
						CRilInstanceNDIS();
						~CRilInstanceNDIS();
	void				Init(PVOID hInstance );
	HRESULT 			NdisSendPacket (RILNDISPACKET* lpNdisPacket);
	HRESULT 			NdisSetGPRSContextActivated (const RILNDISGPRSCONTEXT *lpNdisSetGprsContextActivated );
	HRESULT 			NdisReceivePacketDone (RILNDISPACKET* lpNdisPacket);

private:
	PVOID				m_pCrilInstance;

};

class CRilNDIS
{
public:
					CRilNDIS();
					~CRilNDIS();
	HRESULT 		NdisGetFreeEntry ( DWORD *pIndex );
	void			NdisRemoveNdisEntry ( DWORD ContextID );
	void			NdisAddNdisEntry ( DWORD ContextID, DWORD Index, PVOID pCRilInstance, PVOID pCPdpContext, const RILNDISGPRSCONTEXT *lpRilNdisGprsContext );
	PVOID			NdisPdpContextFromCid( DWORD ContextID );
	PVOID			NdisRilInstanceFromCID( DWORD ContextID );
	void			NdisRilCallbacksFromCID( DWORD ContextID, PVOID *pCallbackContext, RILNDISRECEIVECALLBACK *pfnRilReceiveCallback, RILNDISTRANSMITCALLBACK *pfnRilTransmitCallback, RILNDISSTATUSCALLBACK *pfnRilStatusCallback );
    BOOL            NdisRilGprsContextFromCID( DWORD ContextID, LPRILNDISGPRSCONTEXT pRilGprsContext);
	DWORD			NdisNotifyThread(void);
	void			NdisCloseAllConnections ( void );
	void			NdisShutdownConnection ( DWORD ContextID );
	void			NdisAllocateCommand ( OEMNDISEVENTTYPE Type, DWORD ContextID, LPVOID pCRilInstance, HRESULT CommandID );
	void			NdisRemoveCommand ( HRESULT CommandID );
	BOOL			NdisStart ( HANDLE CancelEvent );
	void			NdisStop( void );
	void			Init(PVOID pHandle );
	BOOL			NdisSupported(void) { return TRUE; };
	HANDLE			NdisGetRxMsgQueueWriteHandle ( void ) { return m_RxMsgQueueWrite; }
	void			NdisConvertConfig ( const OEMNDISIPCONFIG* pOemNdisConfig,	RILNDISIPCONFIG* pRilNdisIpConfig);
	void			AddPdpContextEntry( const RILNDISGPRSCONTEXT *pRilNdisGprsContext, HRESULT AsyncCommandID, PVOID pCRilInstance );
	void			RemovePdpContextEntry( PPDP_CONTEXT_ENTRY pPdpContextEntry );
	BOOL			IsPdpContextListEmpty( void );
	PPDP_CONTEXT_ENTRY			  GetNextPdpContextEntry(  void );
	void			RemoveAndSignalAllPdpContextEntries ( DWORD ContextID );
	void			LockPdpContextList(void){PdpContextLock();}
	void			UnlockPdpContextList(void){PdpContextUnlock();}
	DWORD			MaxContextID ( void ) { return m_NumNdisChannels; }
	DWORD			GetRadioXon(void){return RIL_NDIS_XON;}
	void			ProcessNextContextRequest(void);
	void    		NdisRemoveCallbacks ( DWORD ContextID );




private:
	void			PdpContextLock(void);
	void			PdpContextUnlock(void);
	BOOL			IsPdpContextLocked(void);
	PPDP_CONTEXT_ENTRY	PdpContextEntryGet(void);
	void			DumpPdpContextList ( void );

	POEMNDISCHANNELS				m_pNdisChannels;	// Array of ndis channels in use and available.
	DWORD							m_NumNdisChannels;	// Length of the array above.
	HANDLE							m_NdisNotifyThread; // Handle returned from CreateThread
	DWORD							m_NdisNotifyThreadID;
	CRITICAL_SECTION				m_NdisEventList;
	CAsyncResponse					m_NdisAsyncCommandList;
	PVOID							m_pCRilHandle;
	HANDLE							m_CancelEvent;
	CRITICAL_SECTION				m_ConnectionList;
	HANDLE							m_RxMsgQueue;
	HANDLE							m_RxMsgQueueWrite;
	LIST_ENTRY						m_PdpContextPendingList;
	LIST_ENTRY						m_PdpContextFreeList;
	CRITICAL_SECTION				m_PdpContextCriticalSection;

};

typedef unsigned long  (*PFN_INETADDR)(const char FAR* cp);

#define MAX_ATCGPCO_OPTIONS_LEN NDIS_GPRS_PASSWORD_MAX_LENGTH + NDIS_GPRS_USERNAME_MAX_LENGTH + NDIS_GRPS_DNS_MAX_LENGTH
#define MAX_ATDATA_OPTIONS_LEN 32

typedef enum
{
	CRilATCommandTypeNone,
	CRilATCommandTypeCGPCO,
	CRilATCommandTypeDATA,
	CRilATCommandTypeCGDATA,
	CRilATCommandTypeCGACT,
	CRilRequestTypeMax
} CRilATCommandType;

typedef struct rilatcommand_tag
{
	DWORD		  Size; 		  // @field structure size in bytes
	DWORD		  Operation;		  // @field operation to perform			 
	PVOID		  pData;			  // @field pointer to operation-specific data.
} RILATCOMMAND, *LPRILATCOMMAND;

typedef struct rilatdata_tag
{
	DWORD		  Size; 		  // @field structure size in bytes
	DWORD		  Mode; 			 
	CHAR		  DestDeviceName[MAX_ATDATA_OPTIONS_LEN]; 
	DWORD		  DestDeviceNum;
	DWORD		  DestSubNum;
	CHAR		  Capability[MAX_ATDATA_OPTIONS_LEN];
	CHAR		  SrcDevName[MAX_ATDATA_OPTIONS_LEN];
	DWORD		  SrcDevNum;
	DWORD		  SrcSubNum;
	DWORD		  ContextID;
} RILATDATA, *LPRILATDATA;

typedef struct rilatcgdata_tag
{
	DWORD		  Size; 		  // @field structure size in bytes
	CHAR		  L2P[MAX_ATDATA_OPTIONS_LEN]; 
	DWORD		  ContextID;
} RILATCGDATA, *LPRILATCGDATA;

typedef struct rilatcgpco_tag
{
	DWORD		  Size; 		  // @field structure size in bytes
	DWORD		  Mode; 		  // @field set or query  (0 - set, 1 - query )
	DWORD		  ContextID;		  // @field context ID
	CHAR		  ProtocolOptions[MAX_ATCGPCO_OPTIONS_LEN]; //@field comma separated protocol options string
} RILATCGPCO, *LPRILATCGPCO;

// -----------------------------------------------------------------------------
//
// @doc INTERNAL
//
// @struct RILCGACT |
//
// @comm None
//
// -----------------------------------------------------------------------------
typedef struct rilatcgact_tag
{
	DWORD		  Size; 		  // @field structure size in bytes
	BOOL		  ContextActivation; // @field BOOL true = Activate, false = deactivate
	DWORD		  ContextID;		  // @field context ID
} RILATCGACT, *LPRILATCGACT;
typedef enum  
{ 
	ACTIVATION_STATE_DISCONNECTED,
	ACTIVATION_STATE_CONNECTED,
	ACTIVATION_STATE_CGPCO_SET,
	ACTIVATION_STATE_CGPCO_QUERY,
	ACTIVATION_STATE_DATA,
	ACTIVATION_STATE_ACT,
	ACTIVATION_STATE_CGPADDR,
	ACTIVATION_STATE_CGDATA,
	ACTIVATION_STATE_DEACTIVATE,
	ACTIVATION_STATE_OPEN_FAILED,
	ACTIVATION_STATE_OPEN_SUCCESS,
	ACTIVATION_STATE_REMOTE_DISCONNECT
}RADIO_ACTIVATION_STATES;


class CPdpContext
{
public:
										CPdpContext( IN PVOID pEventNotification );
	virtual 							~CPdpContext();
	HRESULT 							ActivateContext(IN PVOID pActivationParameters);
	DWORD								ProcessObjectsThread ( void );
	void								CloseContext( DWORD ContextID );
	BOOL								IsActivated ( void ) { return (ACTIVATION_STATE_CONNECTED == m_ActivationState); }
	
private:
	HRESULT 							DevSpecific( IN BYTE* pParams,IN DWORD Size, IN BOOL IgnoreResponse );
	HRESULT 							GetGPRSAddress(IN DWORD ContextID );
	HRESULT 							GetGPRSContextActivatedList(void); 
	void								Lock();
	void								Unlock();
	BOOL								IsLocked();
	void								SetOpenComplete ( DWORD RilResultCode  );	
	void								SetNetworkDisconnect ( BOOL GsmRegistered, BOOL GprsAttached );
	void								SetCloseComplete ( void );
	void								SetResultCode ( DWORD ResultCode ) { m_RilResultCode = ResultCode; };
	HANDLE								GetCommandDone ( void ) { return m_CrilAsyncCommandDone; };
	void								InternalIPV4GPRSAddress ( DWORD GPRSIPAddress );
	void								InternalIPV4DNS( DWORD DNS1, DWORD DNS2, DWORD Gateway );
	DWORD								GetActivationState (void) { return m_ActivationState; }

	DWORD			 m_ContextID;
	HANDLE			 m_CrilAsyncCommandDone;
	DWORD			 m_RilResultCode;
	DWORD			 m_ActivationState;
	OEMNDISIPCONFIG  m_OemNdisIpConfig;

	CRITICAL_SECTION m_Lock;

	HANDLE			 m_ProcessObjectsThread; // Handle returned from CreateThread
	DWORD			 m_ProcessObjextsThreadID;
	HANDLE			 m_CrilCancelEvent;
	HANDLE			 m_AppMsgQueue;
	DWORD			 m_WaitForDeactRsp;

	friend HRESULT	 CRilParseSetCGPCO(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, PVOID& pfnParseData);
	friend HRESULT	 CRilParseGetCGPCO(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, PVOID& pfnParseData);
	friend HRESULT	 CRilParseDATA(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, PVOID& pfnParseData);
	friend HRESULT	 CRilParseCGDATA(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, PVOID& pfnParseData);
	friend HRESULT	 CRilParseCGACT(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, PVOID& pfnParseData);
	friend HRESULT	 CRilParseGetGPRSAddress(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, PVOID& pfnParseData);


};

#ifdef __cplusplus
}
#endif



